function [bci, bciDat]=bciP3Stim(bci)

global MEMepoch;
global MEMdata;


stimprm.mode = 0; %train mode
stimprm=bciP3Control(bci,'init',stimprm); % stimulus initialisation

% get the events
bci=bciGenerateEvents(bci,'train');

% estimate size
blocksize  = round(bci.srate *0.1); % 1s when choosing samprate
trainRunDur = sum(bci.eventDur)+bci.preRunDur;
nEpochs = round((trainRunDur-length(bci.events)*bci.RT+10)*bci.init.epochRate);
nRTsamp = round(bci.RT*bci.srate);
epochLabel = zeros(1,nEpochs);
epochOnset = zeros(1,nEpochs);
effectorEvents = zeros(2,nEpochs);
epochTrialID = zeros(1,nEpochs);
badChanMap = zeros(length(bci.preprocChan),nEpochs);

% start buffer reading
pause(bci.preRunDur);
[hdr,bci]=bciReadRecorderHeader(bci,'retry',1);
endsample = hdr.nSamples;
prevSample = endsample;
startSample = endsample;

bciDat.bufferStartTime = endsample / bci.srate;
startTime=GetSecs;
lastOnsetTime=startTime;
lastHitTime = 0;
eventCount=1;
trialCount = 0;
trigCount = 0;
effectorCount=0;
eventList = bci.events;
eventTime = zeros(1,length(eventList)*2);
trigRec = zeros(1,length(eventList)*2);
trigPos = zeros(1,length(eventList)*2);
trigRecTime = zeros(1,length(eventList)*2);
prevTrainSample = 0;
datCount=0;
hdrReadCount=0;
epochCount = 0;
lastEventSamp=inf;
lastEvent=0;
curEvent = -1;
curEventNo = 0;
eventChanged = true;
timeToAddToOnset=[0 bci.eventDur];
nLatencySamp = 0;
if ~bci.param.doReceiveTrigger, % extend trials for constant delayed data transfer
    timeToAddToOnset(find(eventList==8)+1)=timeToAddToOnset(find(eventList==8)+1)+bci.param.roundtripLatency+0.1;
    nLatencySamp = round(bci.param.roundtripLatency*bci.srate);
end
while eventCount<=length(eventList),
    timeStamp=GetSecs;    
    if timeStamp-lastOnsetTime>=timeToAddToOnset(eventCount), %ready for new event
        % wait fbSuccessDur if feedback is used here
%        fprintf('hT:%i dt:%1.3f lE:%i\n',stimprm.hitTarget,timeStamp-lastHitTime,lastEvent);
        if stimprm.hitTarget && timeStamp-lastHitTime>bci.paradigm.fbSuccessDur,
            % show new event
            stimprm.curEvent = eventList(eventCount);
            stimprm.curEventDur = timeToAddToOnset(eventCount+1);
            stimprm = bciP3Control(bci,'newevent',stimprm);
            lastOnsetTime=GetSecs;
            stimprm.eventTimeStamp = lastOnsetTime;
            eventTime(eventCount) = lastOnsetTime-startTime;
            fprintf('nEvt: %i Tm: %3.2f\n',eventList(eventCount),eventTime(eventCount));
            % send event trigger
            if bci.param.doSendTrigger,
                bciSendTrigger(bci,eventList(eventCount));
            end
            if ~bci.param.doReceiveTrigger,
                lastEventSamp=datCount;
                lastEvent=eventList(eventCount);
                eventChanged = true;
            end
            curEventNo=eventCount;
            eventCount=eventCount+1;
        else
            % if last event was flash event 
            % initiate selection (feedback)
            if ~stimprm.hitTarget && lastEvent==8 && curEvent ~=9,
               stimprm.curEvent=lastEvent;
               stimprm = bciP3Control(bci,'select',stimprm);
               if stimprm.hitTarget,                    
                    lastHitTime=GetSecs;
               end
               % auditory feedback?? currently not
               % add feedback event (9) to eventvector, and send trigger
               eventList = [eventList(1:curEventNo) 9 eventList(curEventNo+1:end)];
               timeToAddToOnset = [timeToAddToOnset(1:curEventNo+1) 0 timeToAddToOnset(curEventNo+2:end)];
               eventTime(eventCount) = GetSecs-startTime;
               fprintf('sEvt: %i Tm: %3.2f\n',eventList(eventCount),eventTime(eventCount));

                if stimprm.mostPred>0,
                    effectorCount=effectorCount+1;
                    effectorEvents(:,effectorCount)=[timeStamp-startTime;stimprm.mostPred];
                    % send trigger of effector
                    if bci.param.sendStateTrigger,
                        trigCount=trigCount+1;
                        bciSendTrigger(bci,10+stimprm.mostPred);
                    elseif bci.param.doSendTrigger && stimprm.trialClassified,
                        bciSendTrigger(bci,9); % send feedback trigger
                    end
                end
               
%                % send event trigger
%                if bci.param.doSendTrigger,
%                    bciSendTrigger(bci,eventList(eventCount));
%                end
               if ~bci.param.doReceiveTrigger,
                   lastEventSamp=datCount;
                   lastEvent=eventList(eventCount);
                   eventChanged = true;
               end
               curEventNo=eventCount;
               eventCount=eventCount+1;
            % if last event was selection event and movement initiated but
            % target not reached, check if target reached
            elseif bci.param.doReceiveTrigger && curEvent~=lastEvent,
                % do nothing, just wait until trigger event was received
            else % if none of the conditions is true, go on with next event
                stimprm.hitTarget=true;
            end
        end
    elseif any(lastEvent==8:9)&&stimprm.flashCount<=stimprm.nFlashes, % update the stimulation
        if timeStamp-stimprm.eventTimeStamp>=stimprm.flashOnsetTimes(stimprm.flashCount),
            stimprm = bciP3Control(bci,'flash',stimprm);            
            if bci.param.doSendTrigger && stimprm.objectFlashed,
                bciSendTrigger(bci,bci.paradigm.flashSyncTrigger);
            end
        end
    end
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%% READ DATA 
    % determine number of samples available in buffer
    [hdr,bci] = bciReadRecorderHeader(bci,'retry',1);
    hdrReadCount=hdrReadCount+1;
    newsamples = (hdr.nSamples-prevSample);

    if newsamples>=blocksize && curEventNo>0, %get a new block of data if the length of the available block exceeds the min block size
        %disp('bciGetTrainData: Reading data')
        % determine the samples to process
        begsample  = prevSample+1;
        endsample  = prevSample+newsamples;

        % remember up to where the data was read
        prevSample  = endsample;

        % read data segment from buffer
        MEMdata(:,datCount+1:datCount+newsamples) = ...
                single(bciReadRecorderData(bci, hdr, begsample, endsample));

        curEvent = eventList(curEventNo);
        bciTriggerProcessingInclude;

        datCount=datCount+newsamples;
        if eventChanged,
            % set next expected classifier window onset to event onset
            prevTrainSample = lastEventSamp + nRTsamp - bci.init.nOffset + nLatencySamp;
            eventChanged=false;
            trialCount = trialCount +1;
%             fprintf('%i. event change detected at %3.3fs, available buffer:%3.3fs , event: %i.\n',trialCount,prevTrainSample/bci.srate,datCount/bci.srate,lastEvent);
        end
        while datCount > prevTrainSample + bci.init.nEpochLength,
             fprintf('Potential Epoch: %3.3f-%3.3fs , event: %i\n',prevTrainSample/bci.srate,(prevTrainSample + bci.init.nEpochLength)/bci.srate,lastEvent);
            if prevTrainSample+bci.init.nOffset-lastEventSamp > nRTsamp && ...
               prevTrainSample+bci.init.nOffset-lastEventSamp < bci.srate*(timeToAddToOnset(eventCount)) && ...
                    any(lastEvent==8:9);%lastEvent ==8
                % get next block
                curEpochIdx = (prevTrainSample+1:prevTrainSample+bci.init.nEpochLength);
                if bci.init.doNoiseCancellation,
                    curEpochData = bciNoiseCancellation(...
                        double(MEMdata(bci.preprocChan,curEpochIdx)),...
                        double(MEMdata(bci.referenceChan,curEpochIdx)));
                else
                    curEpochData = MEMdata(bci.preprocChan,curEpochIdx);
                end
                syncOnsets = bciP3Synchronize(bci,MEMdata(bci.init.trigChan,curEpochIdx),...
                                 MEMdata(bci.init.respChan,curEpochIdx),...
                                 stimprm, stimprm.lastTrialEvent, stimprm.stimCount);
                [ep badChan] = bciGetP3Epochs(bci,curEpochData,stimprm,syncOnsets,stimprm.stimCount);
                epochCount = epochCount + 1;
                MEMepoch(:,:,epochCount) = ep;
                epochOnset(epochCount) = prevTrainSample+1;
                badChanMap(:,epochCount) = badChan;
                epochLabel(epochCount) = stimprm.lastTrialEvent;
                epochTrialID(epochCount) = trialCount;
                if abs(GetSecs-startTime-(prevTrainSample+bci.init.nEpochLength)/bci.srate)>1,
                    fprintf('Warning: buffer timing difference > %2.2f s\n',GetSecs-startTime-(prevTrainSample+bci.init.nEpochLength)/bci.srate);
                end
            end
            prevTrainSample = prevTrainSample+bci.init.nWinShift;
        end
    else%if newsamples==0, %if no samples available pause to prevent "failed to create buffer" error
        pause(0.05);
    end % if new samples available
end % while true        

bciDat.eventTime = eventTime(1:curEventNo);
bciDat.trigRecTime = trigRecTime(1:curEventNo);
bciDat.trigRec = trigRec(1:curEventNo);
bciDat.trigPos = trigPos(1:curEventNo);
bciDat.events = eventList(1:curEventNo);
bciDat.effectorEvents=effectorEvents(:,1:effectorCount);
bciDat.nRawData = datCount;
bciDat.nEpochs = epochCount;

bciDat.trainLabel=epochLabel(1:epochCount);
bciDat.trainOnset=epochOnset(1:epochCount);
bciDat.trialID=epochTrialID(1:epochCount);
bciDat.badChanMap=badChanMap(:,1:epochCount);
bciDat.stim = stimprm;